package net.vinote.smart.platform.service;

import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;

import net.vinote.smart.platform.base.Platform;
import net.vinote.smart.platform.base.SysPlatformModify;
import net.vinote.smart.platform.comm.PlatformConst;
import net.vinote.smart.platform.comm.StringFunction;
import net.vinote.smart.platform.module.database.BeanEntityFactory;
import net.vinote.smart.platform.module.database.DBManager;
import net.vinote.smart.platform.module.database.DBManagerFactory;
import net.vinote.smart.platform.module.database.Field;
import net.vinote.smart.platform.module.database.Table;
import net.vinote.smart.platform.module.database.bo.BizObject;
import net.vinote.smart.platform.module.database.bo.DBQuery;
import net.vinote.smart.platform.module.log.RunLogger;
import net.vinote.smart.platform.service.bean.AppInfo;
import net.vinote.smart.platform.service.bean.AppItem;
import net.vinote.smart.platform.service.bean.CodeLibrary;
import net.vinote.smart.platform.service.bean.DataWindowCatalog;
import net.vinote.smart.platform.service.bean.DataWindowEvent;
import net.vinote.smart.platform.service.bean.DataWindowLibrary;
import net.vinote.smart.platform.service.bean.DataWindowPage;
import net.vinote.smart.platform.service.bean.LayoutCatalog;
import net.vinote.smart.platform.service.bean.LayoutItem;
import net.vinote.smart.platform.service.bean.RoleInfo;
import net.vinote.smart.platform.service.bean.SystemParameter;
import net.vinote.smart.platform.service.util.SREConst;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 存储了系统运行所依赖的参数对象
 * 
 * @author 郑俊伟
 * @version 1.0
 * @since JDK1.6
 */
public class SRE extends Platform {
	private static SRE sre;

	private static final RunLogger logger = RunLogger.getLogger();

	SysPlatformModify<Object> sysSREModify = new SysPlatformModify<Object>();

	private SRE() {
	}

	/** 当前系统是否存在合法注册码 */
	private boolean license;

	public static SRE getInstance() {
		if (sre == null) {
			synchronized ("") {
				if (sre == null) {
					sre = new SRE();
					Platform.platform = sre;
				}
			}
		}
		return sre;
	}

	/**
	 * 加载缓存数据
	 * 
	 * @throws SQLException
	 */
	public boolean initializ() throws SQLException {
		super.initializ();
		// 追加资源文件
		getI18nMessage().addI18N("Application", SRE.class.getClassLoader());
		// 加载Service层依赖的action映射配置文件
		loadActionMapping(SRE.class.getClassLoader().getResourceAsStream(
				"action-mapping.xml"));

		loadTables();
		loadSystemParameters();
		reloadCodeLibrary();
		loadDataObjectCatalog();
		loadDataObjectLibrary();
		loadDataObjectEvent();
		loadLayoutCatalog();
		loadLayoutItem();
		loadRoleInfo();
		loadAppInfo();
		loadAppItems();
		loadDataWindowPage();
		Platform.addAttribute(sysSREModify);

		return true;
	}

	/**
	 * 加载action-mapping类
	 */
	public void loadActionMapping(InputStream in) {
		SAXReader read = new SAXReader();
		try {
			read.setValidation(false);
			Document doc = read.read(in);
			Element root = doc.getRootElement();
			String namespace = StringFunction.nullToBlank(root
					.attributeValue("namespace"));
			if ("".equals(namespace)) {
				throw new NullPointerException("namespace is not point out");
			}
			/*
			 * if (getAttribute(SREConst.SRE_PREFIX_ACTION_MAPPING + namespace,
			 * Map.class) != null) { throw new
			 * RuntimeException("namesapce could not reset"); }
			 */
			List<Element> actionList = root.elements("action");
			Map<String, String> actionMap = new Hashtable<String, String>(
					actionList.size());
			for (Element action : actionList) {
				actionMap.put(action.attributeValue("id"),
						action.attributeValue("class"));
			}
			SysPlatformModify<Map<String, String>> actionModify = new SysPlatformModify<Map<String, String>>();
			actionModify.put(SREConst.SRE_PREFIX_ACTION_MAPPING + namespace,
					actionMap);
			addAttribute(actionModify);
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}

	public static Map<String, String> getActionMap(String namespace) {
		return getAttribute(SREConst.SRE_PREFIX_ACTION_MAPPING + namespace,
				Map.class);
	}

	/**
	 * 加载显示模板字段事件
	 * 
	 * @throws SQLException
	 */
	private void loadDataObjectEvent() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("DATAOBJECT_EVENT");
		DBQuery q = bm.createQuery(
				getTable("DATAOBJECT_EVENT").getFieldsName(),
				"ISINUSE='1' order by DONO,FIELDCODE");
		List<BizObject> boList = q.getResultList();
		String curDoNO = null;
		String curFieldCode = null;
		int eventSize = getCodeItems("EventType").size();
		Map<String, String> eventMap = new Hashtable<String, String>(eventSize);
		for (BizObject bo : boList) {

			if ((bo.getAttribute("DONO").equals(curDoNO) && bo.getAttribute(
					"FIELDCODE").equals(curFieldCode))
					|| (curDoNO == null && curFieldCode == null)) {
				DataWindowEvent eventBo = new DataWindowEvent();
				BeanEntityFactory.getInstance().getObject(eventBo, bo);
				eventMap.put(eventBo.getEvent(), eventBo.getScript());
				if (curDoNO == null && curFieldCode == null) {
					curDoNO = bo.getAttribute("DONO");
					curFieldCode = bo.getAttribute("FIELDCODE");
				}
			} else {
				sysSREModify.put(PlatformConst.SRE_PREFIX_DATAOBJECT_EVENT
						+ curDoNO + PlatformConst.SPLIT_$ + curFieldCode,
						eventMap);
				curDoNO = bo.getAttribute("DONO");
				curFieldCode = bo.getAttribute("FIELDCODE");
				eventMap = new Hashtable<String, String>(eventSize);
				DataWindowEvent eventBo = new DataWindowEvent();
				BeanEntityFactory.getInstance().getObject(eventBo, bo);
				eventMap.put(eventBo.getEvent(), eventBo.getScript());
			}
		}
		if (curDoNO != null && curFieldCode != null) {
			sysSREModify.put(PlatformConst.SRE_PREFIX_DATAOBJECT_EVENT
					+ curDoNO + PlatformConst.SPLIT_$ + curFieldCode, eventMap);
		}
	}

	/**
	 * 获取字段的事件集合
	 * 
	 * @param doNo
	 *            显示模板编号
	 * @param fieldCode
	 *            字段编号
	 * @return
	 */
	public static Map<String, String> getDataObjectEvent(String doNo,
			String fieldCode) {
		return Platform.getAttributeMaybeNull(
				PlatformConst.SRE_PREFIX_DATAOBJECT_EVENT + doNo
						+ PlatformConst.SPLIT_$ + fieldCode, Map.class);
	}

	private void loadDataWindowPage() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("datawindow_page");
		List<BizObject> list = bm.createQuery(
				getTable("datawindow_page").getFieldsName(), "1=1")
				.getResultList();
		for (BizObject bo : list) {
			DataWindowPage page = new DataWindowPage();
			BeanEntityFactory.getInstance().getObject(page, bo);
			logger.log(
					Level.FINE,
					"load datawindow page defined table data:"
							+ PlatformConst.SRE_PREFIX_DATAWINDOW_PAGE
							+ page.getPagePath());
			sysSREModify.put(
					PlatformConst.SRE_PREFIX_DATAWINDOW_PAGE
							+ page.getPagePath(), page);
		}
	}

	public static DataWindowPage getDataWindowPage(String pagePath) {
		return Platform.getAttribute(PlatformConst.SRE_PREFIX_DATAWINDOW_PAGE
				+ pagePath, DataWindowPage.class);
	}

	private void loadAppItems() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("app_item");
		List<BizObject> list = bm.createQuery(
				getTable("app_item").getFieldsName(),
				"isinuse='1' ORDER BY APPID ,SORTNO").getResultList();
		List<AppItem> pageItemList = new ArrayList<AppItem>();
		String curAppID = null;
		for (BizObject bo : list) {
			if (bo.getAttribute("APPID").equals(curAppID) || curAppID == null) {
				AppItem item = new AppItem();
				BeanEntityFactory.getInstance().getObject(item, bo);
				pageItemList.add(item);
				if (curAppID == null) {
					curAppID = bo.getAttribute("APPID");
				}
			} else {
				logger.log(Level.FINE, "load app item datas:"
						+ PlatformConst.SRE_PREFIX_APP_ITEM + curAppID);
				sysSREModify.put(PlatformConst.SRE_PREFIX_APP_ITEM + curAppID,
						pageItemList);
				curAppID = bo.getAttribute("APPID");
				pageItemList = new ArrayList<AppItem>();
				AppItem item = new AppItem();
				BeanEntityFactory.getInstance().getObject(item, bo);
				pageItemList.add(item);
			}
		}
		if (curAppID != null) {
			sysSREModify.put(PlatformConst.SRE_PREFIX_APP_ITEM + curAppID,
					pageItemList);
		}
	}

	public static List<AppItem> getAppItems(String appID) {
		return Platform.getAttribute(PlatformConst.SRE_PREFIX_APP_ITEM + appID,
				List.class);
	}

	private void loadAppInfo() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("app_info");
		List<BizObject> list = bm.createQuery(
				getTable("app_info").getFieldsName(),
				"isinuse='1' order by sortNo").getResultList();
		List<AppInfo> appList = new ArrayList<AppInfo>(list.size());
		for (BizObject bo : list) {
			AppInfo appInfo = new AppInfo();
			BeanEntityFactory.getInstance().getObject(appInfo, bo);
			logger.log(Level.FINE, "load app info data:"
					+ PlatformConst.SRE_PREFIX_APP_INFO + appInfo.getAppID());
			sysSREModify.put(
					PlatformConst.SRE_PREFIX_APP_INFO + appInfo.getAppID(),
					appInfo);
			appList.add(appInfo);
		}
		sysSREModify.put(PlatformConst.SRE_PREFIX_APP_INFO_ALL, appList);
	}

	public static AppInfo getAppInfo(String appID) {
		return Platform.getAttribute(PlatformConst.SRE_PREFIX_APP_INFO + appID,
				AppInfo.class);
	}

	public static List<AppInfo> getAllAppInfo() {
		return Platform.getAttribute(PlatformConst.SRE_PREFIX_APP_INFO_ALL,
				List.class);
	}

	private void loadRoleInfo() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("role_info");
		List<BizObject> list = bm.createQuery(
				getTable("role_info").getFieldsName(), "1=1").getResultList();
		for (BizObject bo : list) {
			RoleInfo roleInfo = new RoleInfo();
			BeanEntityFactory.getInstance().getObject(roleInfo, bo);
			logger.log(Level.FINE, "load role_info data:"
					+ PlatformConst.SRE_PREFIX_ROLE_INFO + roleInfo.getRoleID());
			sysSREModify.put(
					PlatformConst.SRE_PREFIX_ROLE_INFO + roleInfo.getRoleID(),
					roleInfo);
		}
	}

	/**
	 * 获取角色定义的实体
	 * 
	 * @param treeNo
	 * @return
	 */
	public static RoleInfo getRoleInfo(String roleID) {
		return Platform.getAttribute(PlatformConst.SRE_PREFIX_ROLE_INFO
				+ roleID, RoleInfo.class);
	}

	/**
	 * 加载页面布局定义 layout_catalog表
	 * 
	 * @throws SQLException
	 */
	private void loadLayoutCatalog() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("LAYOUT_CATALOG");
		DBQuery q = bm.createQuery(getTable("LAYOUT_CATALOG").getFieldsName(),
				null);
		for (BizObject bo : q.getResultList()) {
			logger.log(
					Level.FINE,
					"load layout_catalog data:"
							+ PlatformConst.SRE_PREFIX_LAYOUT_CATALOG
							+ bo.getAttribute("LayoutID"));
			LayoutCatalog catalog = new LayoutCatalog();
			BeanEntityFactory.getInstance().getObject(catalog, bo);
			sysSREModify.put(
					PlatformConst.SRE_PREFIX_LAYOUT_CATALOG
							+ bo.getAttribute("LayoutID"), catalog);
		}
	}

	/**
	 * 获取页面布局对象的实体bean
	 */
	public static LayoutCatalog getLayoutCatalog(String layoutID) {
		return Platform.getAttribute(PlatformConst.SRE_PREFIX_LAYOUT_CATALOG
				+ layoutID, LayoutCatalog.class);
	}

	/**
	 * 加载 layout_item表
	 * 
	 * @throws SQLException
	 */
	private void loadLayoutItem() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("LAYOUT_ITEM");
		DBQuery q = bm.createQuery(getTable("LAYOUT_ITEM").getFieldsName(),
				"ISINUSE='1' order by LAYOUTID,POSITION");
		List<LayoutItem> pageItemList = new ArrayList<LayoutItem>();
		String curLayout = null;
		for (BizObject bo : q.getResultList()) {
			if (bo.getAttribute("LAYOUTID").equals(curLayout)
					|| curLayout == null) {
				LayoutItem item = new LayoutItem();
				BeanEntityFactory.getInstance().getObject(item, bo);
				pageItemList.add(item);
				if (curLayout == null) {
					curLayout = bo.getAttribute("LAYOUTID");
				}
			} else {
				logger.log(Level.FINE, "load layout_item data:"
						+ PlatformConst.SRE_PREFIX_PAGE_ITEM + curLayout);
				sysSREModify.put(
						PlatformConst.SRE_PREFIX_PAGE_ITEM + curLayout,
						pageItemList);
				curLayout = bo.getAttribute("LAYOUTID");
				pageItemList = new ArrayList<LayoutItem>();
				LayoutItem item = new LayoutItem();
				BeanEntityFactory.getInstance().getObject(item, bo);
				pageItemList.add(item);
			}
		}
		if (curLayout != null) {
			sysSREModify.put(PlatformConst.SRE_PREFIX_PAGE_ITEM + curLayout,
					pageItemList);
		}
	}

	public static List<LayoutItem> getLayoutItems(String layoutID) {
		return Platform.getAttribute(PlatformConst.SRE_PREFIX_PAGE_ITEM
				+ layoutID, List.class);
	}

	/**
	 * 加载系统参数表数据
	 * 
	 * @throws SQLException
	 **/
	private void loadSystemParameters() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("system_param");
		List<BizObject> list = bm.createQuery(
				new String[] { "paramname", "paramvalue" }, null)
				.getResultList();
		BizObject paramBo = new BizObject();
		for (BizObject bo : list) {
			paramBo.setAttribute(bo.getAttribute("paramname"),
					bo.getAttribute("paramvalue"));
			bo = null;// 释放
		}
		SystemParameter params = new SystemParameter();
		BeanEntityFactory.getInstance().getObject(params, paramBo);
		sysSREModify.put("systemparam", params);
		list.clear();// 释放
		paramBo = null;// 释放
	}

	/**
	 * 返回系统参数配置对象
	 */
	public static SystemParameter getSystemParameter() {
		return Platform.getAttribute("systemparam", SystemParameter.class);
	}

	/**
	 * 加载Code_library的数据
	 * 
	 * @throws SQLException
	 */
	public void reloadCodeLibrary() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("CODE_LIBRARY");
		DBQuery q = bm.createQuery(getTable("CODE_LIBRARY").getFieldsName(),
				"ISINUSE='1' order by CODENO,SORTNO");
		Map<String, CodeLibrary> codeItemMap = new LinkedHashMap<String, CodeLibrary>();
		String curCodeNO = null;
		for (BizObject bo : q.getResultList()) {
			if (bo.getAttribute("CodeNO").equals(curCodeNO)
					|| curCodeNO == null) {
				CodeLibrary code = new CodeLibrary();
				BeanEntityFactory.getInstance().getObject(code, bo);
				codeItemMap.put(bo.getAttribute("ItemNo"), code);
				if (curCodeNO == null) {
					curCodeNO = bo.getAttribute("CodeNo");
				}
			} else {
				logger.log(Level.FINE, "load code_library data:"
						+ PlatformConst.SRE_PREFIX_CODE_LIBRARY + curCodeNO);
				sysSREModify.put(PlatformConst.SRE_PREFIX_CODE_LIBRARY
						+ curCodeNO, codeItemMap);
				curCodeNO = bo.getAttribute("CodeNO");
				codeItemMap = new LinkedHashMap<String, CodeLibrary>();
				CodeLibrary code = new CodeLibrary();
				BeanEntityFactory.getInstance().getObject(code, bo);
				codeItemMap.put(bo.getAttribute("ItemNo"), code);
			}
		}
		if (curCodeNO != null) {
			sysSREModify.put(PlatformConst.SRE_PREFIX_CODE_LIBRARY + curCodeNO,
					codeItemMap);
		}
	}

	/**
	 * 加载Dataobject_library的数据
	 * 
	 * @throws SQLException
	 */
	private void loadDataObjectLibrary() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("DATAOBJECT_LIBRARY");
		DBQuery q = bm.createQuery(getTable("dataobject_library")
				.getFieldsName(), "ISINUSE='1' order by DONO,SORTNO");
		List<DataWindowLibrary> list = new ArrayList<DataWindowLibrary>();
		String curDoNO = null;
		for (BizObject bo : q.getResultList()) {
			if (bo.getAttribute("DONO").equals(curDoNO) || curDoNO == null) {
				DataWindowLibrary libBo = new DataWindowLibrary();
				BeanEntityFactory.getInstance().getObject(libBo, bo);
				list.add(libBo);
				if (curDoNO == null) {
					curDoNO = bo.getAttribute("DONO");
				}
			} else {
				sysSREModify.put(PlatformConst.SRE_PREFIX_DATAOBJECT_LIBRARY
						+ curDoNO, list);
				curDoNO = bo.getAttribute("DONO");
				list = new ArrayList<DataWindowLibrary>();
				DataWindowLibrary libBo = new DataWindowLibrary();
				BeanEntityFactory.getInstance().getObject(libBo, bo);
				list.add(libBo);
			}
		}
		if (curDoNO != null) {
			sysSREModify.put(PlatformConst.SRE_PREFIX_DATAOBJECT_LIBRARY
					+ curDoNO, list);
		}
	}

	/**
	 * 获取显示模板详情列表
	 **/
	public static List<DataWindowLibrary> getDataWindowLibrary(String doNo) {
		return Platform.getAttribute(
				PlatformConst.SRE_PREFIX_DATAOBJECT_LIBRARY + doNo, List.class);
	}

	/**
	 * 加载Dataobject_Catalog的数据
	 * 
	 * @throws SQLException
	 */
	private void loadDataObjectCatalog() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("DATAOBJECT_CATALOG");
		DBQuery q = bm.createQuery(getTable("dataobject_catalog")
				.getFieldsName(), null);
		for (BizObject bo : q.getResultList()) {
			logger.log(
					Level.FINE,
					"load dataobject_catalog data:"
							+ PlatformConst.SRE_PREFIX_DATAOBJECT_CATALOG
							+ bo.getAttribute("DONO"));
			DataWindowCatalog catalog = new DataWindowCatalog();
			BeanEntityFactory.getInstance().getObject(catalog, bo);
			sysSREModify.put(
					PlatformConst.SRE_PREFIX_DATAOBJECT_CATALOG
							+ bo.getAttribute("DONO"), catalog);
		}
	}

	/** 获取datawindow_catalog对象 */
	public static DataWindowCatalog getDataWindowCatalog(String doNo) {
		return Platform.getAttribute(
				PlatformConst.SRE_PREFIX_DATAOBJECT_CATALOG + doNo,
				DataWindowCatalog.class);
	}

	/**
	 * 加载表结构
	 * 
	 * @throws SQLException
	 */
	private void loadTables() throws SQLException {
		DBManager bm = DBManagerFactory.getInstance("TABLE_OBJECT");
		DBQuery q = bm.createQuery(new String[] { "TABLENAME", "FIELDNAME",
				"COLREMARK", "DATATYPE", "ISKEY" }, "1=1 order by TABLENAME");
		List<BizObject> list = q.getResultList();
		Table table = null;
		for (BizObject bo : list) {
			String tableName = bo.getAttribute("TABLENAME");
			Field field = new Field(tableName, bo.getAttribute("FIELDNAME")
					.toUpperCase(), bo.getAttribute("DATATYPE"), "1".equals(bo
					.getAttribute("ISKEY")), bo.getAttribute("COLREMARK"));
			if (table == null) {
				table = new Table(tableName);
				logger.log(Level.FINE, "load table " + tableName);
			}
			if (!tableName.equals(table.getTableName())) {
				sysSREModify.put(PlatformConst.SRE_PREFIX_TABLE
						+ table.getTableName().toLowerCase(), table);
				table = null;
				table = new Table(tableName);
				logger.log(Level.FINE, "load table " + tableName);
			}
			table.getFields().add(field);
			logger.log(Level.FINE, "load table " + tableName + " column "
					+ field.getFieldName());
		}
		// 确保最后读到的表也被缓存
		if (table != null) {
			sysSREModify.put("Table." + table.getTableName().toLowerCase(),
					table);
			table = null;
		}
	}

	/**
	 * 获取缓存的表对象
	 */
	public static Table getTable(String tableName) {
		Table table = Platform.getAttribute(PlatformConst.SRE_PREFIX_TABLE
				+ tableName, Table.class);
		if (table == null) {
			table = (Table) getInstance().sysSREModify
					.getAttribute(PlatformConst.SRE_PREFIX_TABLE + tableName);
		}
		return table;
	}

	public static Map<String, CodeLibrary> getCodeItems(String codeNo) {
		Map map = Platform.getAttribute(PlatformConst.SRE_PREFIX_CODE_LIBRARY
				+ codeNo, Map.class);
		if (map == null) {
			map = (Map) getInstance().sysSREModify
					.getAttribute(PlatformConst.SRE_PREFIX_CODE_LIBRARY
							+ codeNo);
		}
		return map;
	}

	public boolean hasLicense() {
		return license;
	}

	public void setLicense(boolean flag) {
		license = flag;
	}
}
